#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import logging

import pika
import tornado

from pika import adapters

logger = logging.getLevelName(__name__)



class TornadoConsumer(object):
    EXCHANGE = ''
    EXCHANGE_TYPE = 'direct'
    QUEUE_TPL = '{}-rpc-queue'
    ROUTING_KEY = None

    def __init__(self, name, amqp_url):
        self._name = name
        self._url = amqp_url
        self._queue_name = self.QUEUE_TPL.format(self._name)
        self._conn = None
        self._chann = None
        self._closing = None
        self._consumer_tag = None
        self._exchange_name = '{}'

    def connect(self):
        return adapters.TornadoConnection(pika.URLParameters(self._url), self.on_connection_open)

    def close_connection(self):
        self._conn.close()

    def add_on_connection_close_callback(self):
        self._conn.add_on_close_callback(self.on_connection_closed)

    def on_connection_closed(self, connection, reply_code, reply_text):
        self._conn = None
        if self._closing:
            self._conn.ioloop.stop()
        else:
            self._conn.add_timeout(5, self.reconnect)

    def on_connection_open(self):
        self.add_on_connection_close_callback()
        self.open_channel()

    def reconnect(self):
        if not self._closing:
            self._conn = self.connect()

    def add_on_channel_close_callback(self):
        self._chann.add_on_close_callback(self.on_channel_closed)

    def on_channel_closed(self, channel, reply_code, reply_text):
        self._conn.close()

    def on_channel_open(self, channel):
        self._chann = channel
        self.add_on_channel_close_callback()
        # self.setup_exchange(self.EXCHANGE)

    def setup_exchange(self, exchange_name):
        self._chann.exchange_declare(self.on_exchange_declareok, exchange_name, self.EXCHANGE_TYPE)

    def on_exchange_declareok(self, method_frame):
        self.setup_queue(self._queue_name)
    
    def setup_queue(self, queue_name):
        self._chann.queue_declare(self.on_queue_declareok, queue_name)

    def on_queue_declareok(self):
        self._chann.queue_bind(self.on_bindok, self._queue_name, self.EXCHANGE, self.ROUTING_KEY)

    def add_on_cancel_callback(self):
        self._chann.add_on_cancel_callback(self.on_consumer_cancelled)

    def on_consumer_cancelled(self, method_frame):
        if self._chann:
            self._chann.close()

    def acknowledge_message(self, delivery_tag):
        self._chann.basic_ack(delivery_tag)

    def on_message(self, unused_channel, basic_deliver, properties, body):


        self.acknowledge_message(basic_deliver.delivery_tag)

    def on_cancelok(self, unused_frame):
        self.close_channel()

    def stop_consuming(self):
        if self._chann:
            self._chann.basic_cancel(self.on_cancelok, self._consumer_tag)

    def start_consuming(self):
        self.add_on_cancel_callback()
        self._consumer_tag = self._chann.basic_consume(self.on_message, self._queue_name)
    
    def on_bindok(self, usused_frame):
        self.start_consuming()

    def close_channel(self):
        self._chann.close()

    def open_channel(self):
        self._conn.channel(on_open_callback=self.on_channel_open)

    def run(self):
        self._conn = self.connect()

    def start(self):
        self._conn = self.connect()

    def stop(self):
        self._closing = True
        self.stop_consuming()
        self._conn.ioloop.stop()
